package cn.myjerry.io.others;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

public class SplitFile {
	// 文件的路径
	private String FilePath;
	// 文件名称
	private String FileName;
	// 文件大小
	private long Len;
	// 文件的块数
	private int Size;
	// 每块的大小
	private long BlockSize;
	// 每块的名称
	private List<String> BlockName;
	
	public SplitFile() {
		this.BlockName = new ArrayList<String>();
	}
	public SplitFile(String filePath, int blockSize) {
		this();
		this.FilePath = filePath;
		this.BlockSize = blockSize;
		init();
	}
	public SplitFile(String filePath) {
		this(filePath, 1024);
	}
	/**
	 * 初始化操作 确定块数 确定文件名
	 */
	public void init() {
		File src = null;
		// 文件是否存在
		if(null == FilePath || !((src=new File(FilePath)).exists())) {
			return;
		}
		// 是否为文件夹
		if(src.isDirectory()) {
			return;
		}
		// 文件名
		FileName = src.getName();
		// 计算块数 修正块数实际大小
		Len = src.length();
		if(BlockSize > Len) {
			this.BlockSize = Len;
		}
		// 确定块数
		Size = (int) Math.ceil(Len*1.0/this.BlockSize);
	}
	/**
	 * 确定每块的名称
	 */
	public void initBlockName(String destFile) {
		for(int i=0;i<Size;i++) {
			this.BlockName.add(destFile + "/" + FileName + i + ".txt");
		}
	}
	/**
	 * 文件的分割
	 * 1、第几块
	 * 2、其实位置
	 * 3、实际大小
	 * @param destFile 文件分割存放目录
	 * @throws IOException 
	 */
	public void split(String destFile) throws IOException {
		long startPos = 0;	// 起始点
		long actualBlockSize = this.BlockSize;	// 实际大小
		
		initBlockName(destFile);
		
		// 计算所有块的大小、位置、索引
		for(int i=0;i<Size;i++) {
			if(i == Size-1) {
				actualBlockSize = Len - startPos;
			}
			splitDetail(i, startPos, actualBlockSize);
			startPos += actualBlockSize;
		}
		
	}
	/**
	 * 文件分割细节
	 * 文件的拷贝
	 * @param idx
	 * @param startPos
	 * @param actualBlockSize
	 * @throws IOException 
	 */
	public void splitDetail(int idx, long startPos, long actualBlockSize) throws IOException {
		// 选择流
		RandomAccessFile rnd = new RandomAccessFile(new File(FilePath), "r");
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(this.BlockName.get(idx))));
		rnd.seek(startPos);
		
		byte[] flush = new byte[1024];
		int len = 0;
		
		while(-1 != (len=rnd.read(flush))) {
			if(actualBlockSize - len >= 0) {
				bos.write(flush, 0,len);
				actualBlockSize -= len;
			} else {
				bos.write(flush, 0, (int) actualBlockSize);
				break;
			}
		}
		bos.flush();
		
		rnd.close();
		bos.close();
	}
	public void mergeFile(String destPath) throws IOException {
		File dest = new File(destPath);
		// 选择流
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest, true));
		Vector<InputStream> vi = new Vector<InputStream>();
		SequenceInputStream sis = null;
		
		for(int i=0;i<this.BlockName.size();i++) {
			vi.add(new BufferedInputStream(new FileInputStream(new File(this.BlockName.get(i)))));
		}
		sis = new SequenceInputStream(vi.elements());
		byte[] flush = new byte[1024];
		int len = 0;
		while(-1 != (len=sis.read(flush))) {
			bos.write(flush, 0, len);
		}
		bos.flush();
		sis.close();
		bos.close();
	}
	
	/**
	 * 分割后合并
	 * @param destPath
	 * @throws IOException 
	 */
	public void mergeFile1(String destPath) throws IOException {
		// 创建源
		File dest = new File(destPath);
		
		// 选择流
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest, true));
		BufferedInputStream bis = null;
		
		for(int i=0;i<this.BlockName.size();i++) {
			bis = new BufferedInputStream(new FileInputStream(new File(this.BlockName.get(i))));
			byte[] flush = new byte[1024];
			int len = 0;
			while(-1 != (len=bis.read(flush))) {
				bos.write(flush, 0, len);
			}
		}
		bos.flush();
		
		bis.close();
		bis.close();
	}
	
	public static void main(String[] args) throws IOException {
		SplitFile file = new SplitFile("/Users/zpon/Desktop/test.txt", 100);
		file.split("/Users/zpon/Desktop/test");
		// System.out.println(file.BlockName.toString());
		file.mergeFile("/Users/zpon/Desktop/test09.txt");
	}
}
